package anc.tankshooter.map;

import java.util.ArrayList;
import java.util.Comparator;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.PriorityQueue;


public class AstartFinder implements Comparator<AstartNode>{

	
    
	private PriorityQueue<AstartNode> mOpenList;
	private LinkedList<AstartNode> mCloseList;
	
	public AstartFinder(){
		mOpenList = new PriorityQueue<AstartNode>(1, this);
		mCloseList = new LinkedList<AstartNode>();
		
	}

	@Override
	public int compare(AstartNode firstNode, AstartNode secondNode) {
		firstNode.f = firstNode.g + firstNode.h;
		secondNode.f = secondNode.g + secondNode.h;
		int result =firstNode.f > secondNode.f?1:firstNode.f == secondNode.f?0:-1;
		return result;
	}
	
	public ArrayList<AstartNode> find(int[][] matrix,int i1,int j1,int i2,int j2){
		ArrayList<AstartNode> path = null;
		boolean isSuccess = false;
		AstartNode start = new AstartNode(i1, j1);
		AstartNode end = new AstartNode(i2, j2);
		
		mOpenList.clear();
		mCloseList.clear();
		
		start.g = 0;
		start.h = start.distance(end);
		start.f = start.g + start.h;
		start.mParentNode = null;
		mOpenList.add(start);
		
		while(!mOpenList.isEmpty() && !isSuccess ) {
			AstartNode node = mOpenList.poll();
			mCloseList.add(node);
			
			if(node.equals(end)){
				end.mParentNode=node.mParentNode;
				isSuccess = true;
			}else {
				for (int i = 0; i < 4; i++) {
					int ni = node.i+GameMap.iv[i];
					int nj = node.j+GameMap.jv[i];
					if(ni>=0 && ni<matrix.length && nj>=0 && nj<matrix[0].length && 
							(matrix[ni][nj]==0||(ni==end.i&&nj==end.j))) {
						
						AstartNode nearNode = null;
						
						if(!existCloseList(ni, nj)){
							if(!existOpenList(ni, nj)){
								nearNode = new AstartNode(ni, nj);
								nearNode.g = node.g + nearNode.distance(node);
								nearNode.h = nearNode.distance(end);
								nearNode.f=nearNode.g+nearNode.h;
								nearNode.mParentNode=node;
								this.mOpenList.add(nearNode);
							}else {
								nearNode = openList(ni, nj);
								float g = node.g+ nearNode.distance(node);
								if(g<nearNode.g){
									nearNode.g = g;
									nearNode.h = nearNode.distance(end);
									nearNode.f=nearNode.g+nearNode.h;
									nearNode.mParentNode=node;
								}
							}
						}
					}
					
				}
			}
			
			
		}
		if(isSuccess)
			path = getPath(start,end);
		return path;
	}
	
	/**
	 * Hàm trả về 1 danh sách các Node của đường đi.
	 * Chỉ đc gọi hàm này khi hàm find trả về true
	 * @param end
	 * @return
	 */
	private ArrayList<AstartNode> getPath(AstartNode start,AstartNode end){
		ArrayList<AstartNode> path = new ArrayList<AstartNode>();
		path.add(end);
		while (end.mParentNode!=null && !end.mParentNode.equals(start)) {
			path.add(0,end.mParentNode);
			end = end.mParentNode;
		}
		mCloseList.clear(); mOpenList.clear();
		return path;
	}
	
	private boolean existCloseList(int i,int j){
		boolean isSuccess = false;
		for (Iterator mc = mCloseList.iterator(); !isSuccess && mc.hasNext();) {
			AstartNode node = (AstartNode) mc.next();	
			 isSuccess = (node.i==i&&node.j==j);
		}
		return isSuccess;
	}
	
	private boolean existOpenList(int i,int j){
		boolean isSuccess = false;
		for (Iterator mc = mOpenList.iterator(); !isSuccess && mc.hasNext();) {
			AstartNode node = (AstartNode) mc.next();	
			 isSuccess = (node.i==i&&node.j==j);
		}
		return isSuccess;
	}
	
	private AstartNode openList(int i,int j){
		boolean isSuccess = false;
		AstartNode n =null;
		for (Iterator mc = mOpenList.iterator(); !isSuccess && mc.hasNext();) {
			AstartNode node = (AstartNode) mc.next();	
			 isSuccess = (node.i==i&&node.j==j);
			 if(isSuccess)
				 n= node;
		}
		return n;
	}
	
	private AstartNode closeList(int i,int j){
		boolean isSuccess = false;
		AstartNode n =null;
		for (Iterator mc = mCloseList.iterator(); !isSuccess && mc.hasNext();) {
			AstartNode node = (AstartNode) mc.next();	
			 isSuccess = (node.i==i&&node.j==j);
			 if(isSuccess)
				 n= node;
		}
		return n;
	}
}
